{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 准备工作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 前序数据预处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）故障管理概述.pdf', '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.23）产品描述（5GC业务）.pdf', '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.23）产品描述（上网日志业务）.pdf', '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.23）产品描述（数据业务）.pdf', '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.23）产品描述（端到端业务）.pdf', '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.23）产品描述（语音业务）.pdf']\n",
      "切分后的文件数量：891\n",
      "切分后的字符数（可以用来大致评估 token 数）：319269\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "\"ZXVMAX-S多维价值分析系统告警处理\\n4.修改配置项'Agent的Java堆栈大小'的参数值，重启已修正的flume角色实例；\\n5.等待5分钟，检查告警是否已恢复。如果恢复则结束，如果没恢复则进行第6步；\\n6.以root用户登录产生该告警的服务器；\\n7.执行ps-ef|grepFlumeAgent命令，获取flume服务（FlumeAgent进程）的PID；\\n8.执行jmap-heap<PID>命令，检查flume服务（FlumeAgent进程）'Agent的Java堆栈大小'配置是否生效（蓝色字体的值）。如果不生效则跳到第10步，如果生效则进行第9步；\\n9.等待5分钟，检查告警是否已恢复。如果恢复则结束，如果没恢复则进行第10步；\\n10.备案，等待5分钟，执行步骤8，查看flume进程的堆内存配置是否生效。生效则结束，不生效则通知上级维护人员进一步排查。\\n1.238124010036FlumeAgent进程5分钟意外退出次数告警描述\""
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#!/usr/bin/env python\n",
    "# coding: utf-8\n",
    "\n",
    "# 批量处理文件夹中所有文件\n",
    "import os\n",
    "\n",
    "# 获取folder_path下所有文件路径，储存在file_paths里\n",
    "file_paths = []\n",
    "folder_path = '../data_base/knowledge_path/VMAX-S'\n",
    "for root, dirs, files in os.walk(folder_path):\n",
    "    for file in files:\n",
    "        file_path = os.path.join(root, file)\n",
    "        file_paths.append(file_path)\n",
    "print(file_paths)\n",
    "\n",
    "from langchain.document_loaders.pdf import PyMuPDFLoader\n",
    "# from langchain.document_loaders.markdown import UnstructuredMarkdownLoader\n",
    "\n",
    "# 遍历文件路径并把实例化的loader存放在loaders里\n",
    "loaders = []\n",
    "\n",
    "for file_path in file_paths:\n",
    "    file_type = file_path.split('.')[-1]\n",
    "    if file_type == 'pdf':\n",
    "        loaders.append(PyMuPDFLoader(file_path))\n",
    "    else:\n",
    "        print(f\"Unsupported file type: {file_type} for file {file_path}\")\n",
    "\n",
    "# 下载文件并存储到text\n",
    "# 加载所有文档内容到 texts\n",
    "texts = []\n",
    "for loader in loaders:\n",
    "    texts.extend(loader.load())  # 关键步骤：初始化 texts\n",
    "\n",
    "    \n",
    "# 作数据清洗\n",
    "# 修改后的数据清洗部分（替换原始代码中对应段落）\n",
    "import re\n",
    "\n",
    "# 预编译正则表达式（提升效率）\n",
    "linebreak_pattern = re.compile(\n",
    "    r'(?<![\\\\u4e00-\\\\u9fff])\\n(?![\\\\u4e00-\\\\u9fff])',  # 负向断言匹配非中文环境换行\n",
    "    flags=re.DOTALL\n",
    ")\n",
    "space_pattern = re.compile(r'[ 　]+')  # 匹配半角/全角空格\n",
    "special_chars = ['•', '▪', '▫', '▶', '®', '©']  # 可扩展的干扰符号列表\n",
    "\n",
    "# 替换原始代码中的清洗循环\n",
    "for text in texts:\n",
    "    # 1. 清理非中文环境换行\n",
    "    text.page_content = re.sub(\n",
    "        linebreak_pattern,\n",
    "        lambda m: m.group().replace('\\n', ''),\n",
    "        text.page_content\n",
    "    )\n",
    "\n",
    "    # 2. 批量清理特殊符号\n",
    "    for char in special_chars:\n",
    "        text.page_content = text.page_content.replace(char, '')\n",
    "\n",
    "    # 3. 安全删除空格（保留URL等特殊场景）\n",
    "    text.page_content = space_pattern.sub('', text.page_content)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "#导入文本分割器\n",
    "from langchain_text_splitters import RecursiveCharacterTextSplitter\n",
    "''' \n",
    "* RecursiveCharacterTextSplitter 递归字符文本分割\n",
    "RecursiveCharacterTextSplitter 将按不同的字符递归地分割(按照这个优先级[\"\\n\\n\", \"\\n\", \" \", \"\"])，\n",
    "    这样就能尽量把所有和语义相关的内容尽可能长时间地保留在同一位置\n",
    "RecursiveCharacterTextSplitter需要关注的是4个参数：\n",
    "\n",
    "* separators - 分隔符字符串数组\n",
    "* chunk_size - 每个文档的字符数量限制\n",
    "* chunk_overlap - 两份文档重叠区域的长度\n",
    "* length_function - 长度计算函数\n",
    "'''\n",
    "\n",
    "\n",
    "# 知识库中单段文本长度\n",
    "CHUNK_SIZE = 512\n",
    "\n",
    "# 知识库中相邻文本重合长度\n",
    "OVERLAP_SIZE = 50\n",
    "\n",
    "\n",
    "# 使用递归字符文本分割器\n",
    "text_splitter = RecursiveCharacterTextSplitter(\n",
    "    chunk_size=CHUNK_SIZE,\n",
    "    chunk_overlap=OVERLAP_SIZE\n",
    ")\n",
    "\n",
    "\n",
    "split_docs = text_splitter.split_documents(texts)\n",
    "print(f\"切分后的文件数量：{len(split_docs)}\")\n",
    "\n",
    "\n",
    "\n",
    "print(f\"切分后的字符数（可以用来大致评估 token 数）：{sum([len(doc.page_content) for doc in split_docs])}\")\n",
    "\n",
    "\n",
    "\n",
    "split_docs[300].page_content\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 前序embedding模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# ZhipuAIEmbeddings模型\n",
    "# import os\n",
    "# from dotenv import load_dotenv, find_dotenv\n",
    "\n",
    "# _ = load_dotenv(find_dotenv())\n",
    "\n",
    "# from langchain_community.embeddings import ZhipuAIEmbeddings\n",
    "\n",
    "# my_emb = ZhipuAIEmbeddings(\n",
    "#     model=\"embedding-2\",\n",
    "#     api_key = os.environ['ZHIPUAI_API_KEY'],\n",
    "# )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_ollama.embeddings import OllamaEmbeddings\n",
    "\n",
    "# 初始化嵌入模型\n",
    "my_emb = OllamaEmbeddings(\n",
    "    base_url='http://localhost:11434',\n",
    "    model=\"bge-m3:latest\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 数据库选型：Chroma"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构建Chroma向量库"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "涉及到的API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "# langchain_chroma.vectordbs.Chroma\n",
    "# class langchain_chroma.vectordbs.Chroma(\n",
    "#     collection_name: str = 'langchain', \n",
    "# embedding_function: Embeddings | None = None, \n",
    "# persist_directory: str | None = None, \n",
    "# client_settings: Settings | None = None, \n",
    "# collection_metadata: Dict | None = None, \n",
    "# client: ClientAPI | None = None, \n",
    "# relevance_score_fn: Callable[[float], float] | None = None, \n",
    "# create_collection_if_not_exists: bool | None = True)\n",
    "\n",
    "\n",
    "# classmethod from_documents(\n",
    "#     documents: List[Document], \n",
    "# embedding: Embeddings | None = None, \n",
    "# ids: List[str] | None = None, \n",
    "# collection_name: str = 'langchain', \n",
    "# persist_directory: str | None = None, \n",
    "# client_settings: Settings | None = None, \n",
    "# client: ClientAPI | None = None, \n",
    "# collection_metadata: Dict | None = None, \n",
    "# **kwargs: Any)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "直接调用Chroma.from_documents (推荐)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "向量数据库已成功持久化到磁盘。\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\will\\AppData\\Local\\Temp\\ipykernel_2896\\2982754907.py:28: LangChainDeprecationWarning: Since Chroma 0.4.x the manual persistence method is no longer supported as docs are automatically persisted.\n",
      "  vectordb.persist()\n"
     ]
    }
   ],
   "source": [
    "# 汇总\n",
    "\n",
    "import os\n",
    "from langchain_community.vectorstores import Chroma\n",
    "# from langchain_chroma.vectorstores import Chroma\n",
    "from langchain_ollama.embeddings import OllamaEmbeddings\n",
    "\n",
    "# 定义持久化目录\n",
    "persist_directory = '../data_base/vector_db/chroma-vmax'\n",
    "\n",
    "# 创建嵌入模型\n",
    "my_emb = OllamaEmbeddings(\n",
    "    base_url='http://localhost:11434',\n",
    "    model=\"bge-m3:latest\"\n",
    ")\n",
    "\n",
    "try:\n",
    "    # 初始化 Chroma 向量数据库\n",
    "    vectordb = Chroma.from_documents(\n",
    "        documents=split_docs[0:10],  # 为了速度，只选择前 20 个切分的 doc 进行生成\n",
    "        # documents=split_docs,  # 为了速度，只选择前 20 个切分的 doc 进行生成\n",
    "        embedding=my_emb,\n",
    "        # collection_name=\"test1\", # 如果不指定默认为langchain\n",
    "        persist_directory=persist_directory, # 允许我们将persist_directory目录保存到磁盘上\n",
    "    )\n",
    "    \n",
    "    # 持久化向量数据库\n",
    "    vectordb.persist()\n",
    "    print(\"向量数据库已成功持久化到磁盘。\")\n",
    "except Exception as e:\n",
    "    print(f\"持久化过程中发生错误: {e}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上代码会报错： 持久化过程中发生错误: Error code: 400, with error text {\"error\":{\"code\":\"1214\",\"message\":\"input数组最大不得超过64条\"}}\n",
    "\n",
    "建议分批次导入"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from langchain_community.vectorstores import Chroma\n",
    "from langchain_community.embeddings import ZhipuAIEmbeddings\n",
    "\n",
    "# 定义持久化目录\n",
    "persist_directory = '../data_base/vector_db/chroma-vmax'\n",
    "\n",
    "# 创建嵌入模型\n",
    "my_emb = OllamaEmbeddings(\n",
    "    base_url='http://localhost:11434',\n",
    "    model=\"bge-m3:latest\"\n",
    ")\n",
    "\n",
    "# 定义每批处理的文档数量\n",
    "batch_size = 30\n",
    "\n",
    "split_docs=split_docs[:100]\n",
    "\n",
    "try:\n",
    "    # 计算总批次数\n",
    "    total_batches = (len(split_docs) + batch_size - 1) // batch_size\n",
    "    \n",
    "    # 初始化向量数据库（如果是第一次创建）\n",
    "    vectordb = None\n",
    "    \n",
    "    for batch_num in range(total_batches):\n",
    "        # 计算当前批次的起始和结束索引\n",
    "        start_idx = batch_num * batch_size\n",
    "        end_idx = min((batch_num + 1) * batch_size, len(split_docs))\n",
    "        \n",
    "        # 获取当前批次的文档\n",
    "        batch_docs = split_docs[start_idx:end_idx]\n",
    "        \n",
    "        print(f\"正在处理第 {batch_num + 1}/{total_batches} 批文档 (文档 {start_idx}-{end_idx-1})\")\n",
    "        \n",
    "        if batch_num == 0:\n",
    "            # 第一次创建向量数据库\n",
    "            vectordb = Chroma.from_documents(\n",
    "                collection_name='vmaxs',\n",
    "                documents=batch_docs,\n",
    "                embedding=my_emb,\n",
    "                persist_directory=persist_directory\n",
    "            )\n",
    "        else:\n",
    "            # 后续批次添加到现有集合\n",
    "            vectordb.add_documents(batch_docs)\n",
    "        \n",
    "        # 每批处理后持久化\n",
    "        vectordb.persist()\n",
    "        print(f\"第 {batch_num + 1} 批文档已成功导入并持久化\")\n",
    "    \n",
    "    print(\"所有文档已成功导入并持久化到向量数据库。\")\n",
    "    \n",
    "except Exception as e:\n",
    "    print(f\"处理过程中发生错误: {e}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "也可以参考数据库官方文档，进行操作： https://docs.trychroma.com/docs/overview/introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 连接Chroma数据库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 数据库路径 ./chroma2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chromadb\n",
    "chroma_client  = chromadb.PersistentClient(path=\"../data_base/vector_db/chroma-vmax\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['langchain', 'vmax-s']"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "chroma_client.list_collections()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取一个存在的Collection对象\n",
    "collection = chroma_client.get_collection(\"langchain\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "collection.count()  #  returns the number of items in the collection."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# collection.peek()  # returns a list of the first 10 items in the collection."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'ids': ['892b501d-248d-4b96-9fec-64f2efab9f86', '2eb6c129-4d1f-4eed-a5c7-bc5e2e51a6ce', '459ef97b-04a3-4f0b-909b-404e7e955738', '2c67d77b-d2a4-4f0d-85e7-1bf5ccabd016', 'df6c4497-9a83-4bff-ba7d-025ffd5290ac', '0d1ffdf7-c6cb-4866-8363-b87d50390e45', 'a6699ba4-b2d5-4a8a-a62b-5dc5828486ac', 'fcea22f0-3b56-436a-b976-be43e68f0acc', 'f07074ea-db04-4d4a-8a45-902b3ca108fc', '00364fd3-9444-42c4-865c-0dc5f83b4ba9'], 'embeddings': None, 'documents': ['ZXVMAX-S\\n多维价值分析系统告警处理产品版本：V6.20.80.02\\n中兴通讯股份有限公司地址：深圳市南山区高新技术产业园科技南路中兴通讯大厦邮编：518057\\n电话：0755-26770800\\n\\xa0\\xa0\\xa0400-8301118\\n\\xa0\\xa0\\xa0\\xa0\\xa0\\xa0\\n800-8301118（座机）技术支持网站：http://support.zte.com.cn电子邮件：800@zte.com.cn', '法律声明本资料著作权属中兴通讯股份有限公司所有。未经著作权人书面许可，任何单位或个人不得以任何方式摘录、复制或翻译。侵权必究。\\xa0和\\xa0是中兴通讯股份有限公司的注册商标。中兴通讯产品的名称和标志是中兴通讯的专有标志或注册商标。在本手册中提及的其他产品或公司的名称可能是其各自所有者的商标或商名。在未经中兴通讯或第三方商标或商名所有者事先书面同意的情况下，本手册不以任何方式授予阅读者任何使用本手册上出现的任何标记的许可或权利。本产品符合关于环境保护和人身安全方面的设计要求，产品的存放、使用和弃置应遵照产品手册、相关合同或相关国法律、法规的要求进行。如果本产品进行改进或技术变更，恕不另行专门通知。当出现产品改进或者技术变更时，您可以通过中兴通讯技术支持网站http://support.zte.com.cn查询有关信息。\\xa0第三方嵌入式软件使用限制声明：如果与本产品配套交付了Oracle、Sybase/SAP、Veritas、Microsoft、VMware、Redhat这些第三方嵌入式软件，只允许作为本产品的组件，与本产品捆绑使用。当本产品被废弃时，这些第三方软件的授权许可同时作废，不可转移。这些嵌入式软件由ZTE给最终', '捆绑使用。当本产品被废弃时，这些第三方软件的授权许可同时作废，不可转移。这些嵌入式软件由ZTE给最终用户提供技术支持。修订历史资料版本发布日期更新说明', 'R1.0\\n2022-06-20\\n第一次发布资料编号∶SJ-20220623151803-011\\n发布日期∶2022-06-20（R1.0）', '目录\\n1DAP告警...........................................................1\\n1.1301节点状态异常.......................................................8\\n1.2302系统状态异常.......................................................9\\n1.31017HDFSNameNode主备切换............................................9\\n1.42010(节点级)元数据故障...............................................10\\n1.5100001Agent服务异常..................................................10\\n1.6100004主机离线.......................................................11', '1.7100600用户密码即将失效...............................................11\\n1.8100601NTP服务不可用..................................................12\\n1.9100602NTP服务时钟源不一致............................................12\\n1.10100603NTP时钟偏移超过阈值...........................................13\\n1.11110007Mode切换告警..................................................13\\n1.12130007ResourceManager角色变化告警...................................14\\n1.13140000Master主备切换告警............................................15', '1.14141001HBase元数据不一致...........................................15\\n1.15141001localhbase元数据异常.........................................15\\n1.16180000Master状态切换告警............................................16\\n1.17190000Storm服务nimbus角色HA主备切换频率.............................17\\n1.18110010001主机CPU利用率..............................................17\\n1.19110010002主机等待IO的CPU百分比......................................17\\n1.20110020006主机物理内存利用率.........................................18', '1.21110020007主机交换空间利用率.........................................18\\n1.22110030011主机业务网卡带宽利用率.....................................19\\n1.23110030012主机业务网卡网络时延.......................................19\\n1.24110030013主机业务网卡网络丢包率.....................................20\\n1.25110040020主机磁盘带宽使用率.........................................20\\n1.26110050023主机文件系统空间使用率.....................................21\\n1.27111010001Zookeeper进程CPU使用率.....................................21', '1.28111010002Zookeeper进程MEM使用率.....................................21\\n1.29111010003Zookeeper进程客户端有效连接数..............................22\\n1.30111010006Zookeeper进程待处理的请求个数..............................22\\n1.31111010024Zookeeper进程文件描述符使用百分比..........................23\\n1.32111010027Zookeeper进程数据目录可用空间大小..........................24\\nI', '1.33111010028Zookeeper进程事务日志目录可用空间大小......................25\\n1.34111010029Zookeeper进程客户端最大请求时延占比超时时长................26\\n1.35111010030Zookeeper进程5分钟意外退出次数.............................27\\n1.36111010037Zookeeper进程每分钟内存回收时间所占的百分比................27\\n1.37112010003HDFS服务文件系统使用率.....................................28\\n1.38112010004HDFS服务RPC在交互中平均等待时间............................28\\n1.39112010005HDFS服务RPC在最近的交互中平均操作时间......................28\\n1.40112010019NameNode节点堆内存使用百分比...............................29'], 'uris': None, 'data': None, 'metadatas': [{'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 0, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}, {'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 1, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}, {'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 1, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}, {'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 1, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}, {'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 2, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}, {'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 2, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}, {'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 2, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}, {'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 2, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}, {'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 2, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}, {'author': '', 'creationDate': \"D:20220623163422+08'00'\", 'creationdate': '2022-06-23T16:34:22+08:00', 'creator': 'DITA Open Toolkit', 'file_path': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'format': 'PDF 1.4', 'keywords': '', 'modDate': '', 'moddate': '', 'page': 3, 'producer': 'Apache FOP Version 2.3', 'source': '../data_base/knowledge_path/VMAX-S\\\\ZXVMAX-S（V6.20.80.02）告警处理.pdf', 'subject': '', 'title': '目录', 'total_pages': 330, 'trapped': ''}], 'included': [<IncludeEnum.documents: 'documents'>, <IncludeEnum.metadatas: 'metadatas'>]}\n"
     ]
    }
   ],
   "source": [
    "# 获取所有数据（默认不返回嵌入向量）\n",
    "all_data = collection.get()\n",
    "print(all_data)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 向量检索\n",
    "### 3.1 相似度检索\n",
    "Chroma的相似度搜索使用的是余弦距离，即：\n",
    "$$\n",
    "similarity = cos(A, B) = \\frac{A \\cdot B}{\\parallel A \\parallel \\parallel B \\parallel} = \\frac{\\sum_1^n a_i b_i}{\\sqrt{\\sum_1^n a_i^2}\\sqrt{\\sum_1^n b_i^2}}\n",
    "$$\n",
    "其中$a_i$、$b_i$分别是向量$A$、$B$的分量。\n",
    "\n",
    "当你需要数据库返回严谨的按余弦相似度排序的结果时可以使用`similarity_search`函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用Chroma.from_documents时，用这个方法： "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "question=\"vmax\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "检索到的内容数：3\n"
     ]
    }
   ],
   "source": [
    "sim_docs = vectordb.similarity_search(question,k=3)\n",
    "print(f\"检索到的内容数：{len(sim_docs)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "检索到的第0个内容: \n",
      "ZXVMAX-S\n",
      "多维价值分析系统告警处理产品版本：V6.20.80.02\n",
      "中兴通讯股份有限公司地址：深圳市南山区高新技术产业园科技南路中兴通讯大厦邮编：518057\n",
      "电话：0755-26770800\n",
      "   400-8301118\n",
      "      \n",
      "800-8301118（座机）技术支持网站：http://support.zte.com.cn电子邮件：800@zte.com.cn\n",
      "--------------\n",
      "检索到的第1个内容: \n",
      "ZXVMAX-S\n",
      "多维价值分析系统告警处理产品版本：V6.20.80.02\n",
      "中兴通讯股份有限公司地址：深圳市南山区高新技术产业园科技南路中兴通讯大厦邮编：518057\n",
      "电话：0755-26770800\n",
      "   400-8301118\n",
      "      \n",
      "800-8301118（座机）技术支持网站：http://support.zte.com.cn电子邮件：800@zte.com.cn\n",
      "--------------\n",
      "检索到的第2个内容: \n",
      "1.14141001HBase元数据不一致...........................................15\n",
      "1.15141001localhbase元数据异常.........................................15\n",
      "1.16180000Master状态切换告警..........................................\n",
      "--------------\n"
     ]
    }
   ],
   "source": [
    "for i, sim_doc in enumerate(sim_docs):\n",
    "    print(f\"检索到的第{i}个内容: \\n{sim_doc.page_content[:200]}\", end=\"\\n--------------\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 MMR检索\n",
    "如果只考虑检索出内容的相关性会导致内容过于单一，可能丢失重要信息。\n",
    "\n",
    "最大边际相关性 (`MMR, Maximum marginal relevance`) 可以帮助我们在保持相关性的同时，增加内容的丰富度。\n",
    "\n",
    "核心思想是在已经选择了一个相关性高的文档之后，再选择一个与已选文档相关性较低但是信息丰富的文档。这样可以在保持相关性的同时，增加内容的多样性，避免过于单一的结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "mmr_docs = vectordb.max_marginal_relevance_search(question,k=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MMR 检索到的第0个内容: \n",
      "ZXVMAX-S\n",
      "多维价值分析系统告警处理产品版本：V6.20.80.02\n",
      "中兴通讯股份有限公司地址：深圳市南山区高新技术产业园科技南路中兴通讯大厦邮编：518057\n",
      "电话：0755-26770800\n",
      "   400-8301118\n",
      "      \n",
      "800-8301118（座机）技术支持网站：http://support.zte.com.cn电子邮件：800@zte.com.cn\n",
      "--------------\n",
      "MMR 检索到的第1个内容: \n",
      "1.33111010028Zookeeper进程事务日志目录可用空间大小......................25\n",
      "1.34111010029Zookeeper进程客户端最大请求时延占比超时时长................26\n",
      "1.35111010030Zookeeper进程5分钟意外退出次数.............................27\n",
      "1.36111010037Zoo\n",
      "--------------\n",
      "MMR 检索到的第2个内容: \n",
      "R1.0\n",
      "2022-06-20\n",
      "第一次发布资料编号∶SJ-20220623151803-011\n",
      "发布日期∶2022-06-20（R1.0）\n",
      "--------------\n"
     ]
    }
   ],
   "source": [
    "for i, sim_doc in enumerate(mmr_docs):\n",
    "    print(f\"MMR 检索到的第{i}个内容: \\n{sim_doc.page_content[:200]}\", end=\"\\n--------------\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 数据库选型：Milvus"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 构建Milvus向量库"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from langchain_community.vectorstores import Milvus\n",
    "from langchain_core.documents import Document\n",
    "\n",
    "\n",
    "# 创建嵌入模型\n",
    "my_emb = OllamaEmbeddings(\n",
    "    base_url='http://localhost:11434',\n",
    "    model=\"bge-m3:latest\"\n",
    ")\n",
    "\n",
    "# 向量库创建\n",
    "connection_args = {\n",
    "    \"host\": \"192.168.0.188\",\n",
    "    \"port\": \"19530\",\n",
    "}\n",
    "\n",
    "\n",
    "# 定义每批处理的文档数量\n",
    "batch_size = 30\n",
    "\n",
    "# 如果只想导入部分数据\n",
    "# split_docs = split_docs[:3]\n",
    "try:\n",
    "    # 计算总批次数\n",
    "    total_batches = (len(split_docs) + batch_size - 1) // batch_size\n",
    "    \n",
    "    # 初始化向量数据库（如果是第一次创建）\n",
    "    vectordb = None\n",
    "    \n",
    "    for batch_num in range(total_batches):\n",
    "        # 计算当前批次的起始和结束索引\n",
    "        start_idx = batch_num * batch_size\n",
    "        end_idx = min((batch_num + 1) * batch_size, len(split_docs))\n",
    "        \n",
    "        # 获取当前批次的文档\n",
    "        batch_docs = split_docs[start_idx:end_idx]\n",
    "        \n",
    "        print(f\"正在处理第 {batch_num + 1}/{total_batches} 批文档 (文档 {start_idx}-{end_idx-1})\")\n",
    "\n",
    "        if batch_num == 0:\n",
    "            # 第一次创建向量数据库\n",
    "            vectordb = Milvus.from_documents(\n",
    "            documents=batch_docs,\n",
    "            embedding=my_emb,\n",
    "            collection_name=\"vmaxs\",\n",
    "            drop_old=False,\n",
    "            connection_args=connection_args,\n",
    "            )\n",
    "\n",
    "        else:\n",
    "            # 后续批次添加到现有集合\n",
    "            vectordb.add_documents(batch_docs)\n",
    "        \n",
    "        # 每批处理后持久化\n",
    "        # vectordb.persist()\n",
    "        print(f\"第 {batch_num + 1} 批文档已成功导入并持久化\")\n",
    "    \n",
    "    print(\"所有文档已成功导入并持久化到向量数据库。\")\n",
    "    \n",
    "except Exception as e:\n",
    "    print(f\"处理过程中发生错误: {e}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_community.vectorstores import Milvus\n",
    "\n",
    "my_emb = OllamaEmbeddings(base_url='http://localhost:11434', model=\"bge-m3:latest\")\n",
    "\n",
    "connection_args = {\n",
    "    \"uri\": \"tcp://129.201.70.35:19530\"\n",
    "}\n",
    "# Milvus 连接参数\n",
    "vectordb = Milvus(\n",
    "        embedding_function=my_emb,\n",
    "        collection_name=\"Vmaxs\",  # Milvus 集合名称\n",
    "        connection_args=connection_args,\n",
    "    )\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\will\\AppData\\Local\\Temp\\ipykernel_2896\\155588456.py:6: LangChainDeprecationWarning: The class `Milvus` was deprecated in LangChain 0.2.0 and will be removed in 1.0. An updated version of the class exists in the :class:`~langchain-milvus package and should be used instead. To use it run `pip install -U :class:`~langchain-milvus` and import as `from :class:`~langchain_milvus import MilvusVectorStore``.\n",
      "  vectordb = Milvus(\n",
      "Failed to create new connection using: 6035000a1b3241f0af07ef903e49f4c4\n"
     ]
    },
    {
     "ename": "MilvusException",
     "evalue": "<MilvusException: (code=2, message=Fail connecting to server on 192.168.0.188:19530, illegal connection params or server unavailable)>",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mFutureTimeoutError\u001b[39m                        Traceback (most recent call last)",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\pymilvus\\client\\grpc_handler.py:149\u001b[39m, in \u001b[36mGrpcHandler._wait_for_channel_ready\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m    148\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m149\u001b[39m     \u001b[43mgrpc\u001b[49m\u001b[43m.\u001b[49m\u001b[43mchannel_ready_future\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_channel\u001b[49m\u001b[43m)\u001b[49m\u001b[43m.\u001b[49m\u001b[43mresult\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    150\u001b[39m     \u001b[38;5;28mself\u001b[39m._setup_identifier_interceptor(\u001b[38;5;28mself\u001b[39m._user, timeout=timeout)\n",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\grpc\\_utilities.py:162\u001b[39m, in \u001b[36m_ChannelReadyFuture.result\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m    161\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mresult\u001b[39m(\u001b[38;5;28mself\u001b[39m, timeout: Optional[\u001b[38;5;28mfloat\u001b[39m] = \u001b[38;5;28;01mNone\u001b[39;00m) -> \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m162\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_block\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\grpc\\_utilities.py:106\u001b[39m, in \u001b[36m_ChannelReadyFuture._block\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m    105\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m remaining < \u001b[32m0\u001b[39m:\n\u001b[32m--> \u001b[39m\u001b[32m106\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m grpc.FutureTimeoutError()\n\u001b[32m    107\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n",
      "\u001b[31mFutureTimeoutError\u001b[39m: ",
      "\nThe above exception was the direct cause of the following exception:\n",
      "\u001b[31mMilvusException\u001b[39m                           Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m      3\u001b[39m my_emb = OllamaEmbeddings(base_url=\u001b[33m'\u001b[39m\u001b[33mhttp://localhost:11434\u001b[39m\u001b[33m'\u001b[39m, model=\u001b[33m\"\u001b[39m\u001b[33mbge-m3:latest\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m      5\u001b[39m \u001b[38;5;66;03m# Milvus 连接参数\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m vectordb = \u001b[43mMilvus\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m      7\u001b[39m \u001b[43m        \u001b[49m\u001b[43membedding_function\u001b[49m\u001b[43m=\u001b[49m\u001b[43mmy_emb\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m      8\u001b[39m \u001b[43m        \u001b[49m\u001b[43mcollection_name\u001b[49m\u001b[43m=\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mVmaxs\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m  \u001b[49m\u001b[38;5;66;43;03m# Milvus 集合名称\u001b[39;49;00m\n\u001b[32m      9\u001b[39m \u001b[43m        \u001b[49m\u001b[43mconnection_args\u001b[49m\u001b[43m=\u001b[49m\u001b[43m{\u001b[49m\n\u001b[32m     10\u001b[39m \u001b[43m            \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mhost\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43m192.168.0.188\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m  \u001b[49m\u001b[38;5;66;43;03m# Milvus 服务器地址\u001b[39;49;00m\n\u001b[32m     11\u001b[39m \u001b[43m            \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mport\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43m19530\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m  \u001b[49m\u001b[38;5;66;43;03m# Milvus 默认端口\u001b[39;49;00m\n\u001b[32m     12\u001b[39m \u001b[43m        \u001b[49m\u001b[43m}\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m     13\u001b[39m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\langchain_core\\_api\\deprecation.py:221\u001b[39m, in \u001b[36mdeprecated.<locals>.deprecate.<locals>.finalize.<locals>.warn_if_direct_instance\u001b[39m\u001b[34m(self, *args, **kwargs)\u001b[39m\n\u001b[32m    219\u001b[39m     warned = \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[32m    220\u001b[39m     emit_warning()\n\u001b[32m--> \u001b[39m\u001b[32m221\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mwrapped\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\langchain_community\\vectorstores\\milvus.py:206\u001b[39m, in \u001b[36mMilvus.__init__\u001b[39m\u001b[34m(self, embedding_function, collection_name, collection_description, collection_properties, connection_args, consistency_level, index_params, search_params, drop_old, auto_id, primary_field, text_field, vector_field, metadata_field, partition_key_field, partition_names, replica_number, timeout, num_shards)\u001b[39m\n\u001b[32m    204\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m connection_args \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m    205\u001b[39m     connection_args = DEFAULT_MILVUS_CONNECTION\n\u001b[32m--> \u001b[39m\u001b[32m206\u001b[39m \u001b[38;5;28mself\u001b[39m.alias = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_create_connection_alias\u001b[49m\u001b[43m(\u001b[49m\u001b[43mconnection_args\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    207\u001b[39m \u001b[38;5;28mself\u001b[39m.col: Optional[Collection] = \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m    209\u001b[39m \u001b[38;5;66;03m# Grab the existing collection if it exists\u001b[39;00m\n",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\langchain_community\\vectorstores\\milvus.py:289\u001b[39m, in \u001b[36mMilvus._create_connection_alias\u001b[39m\u001b[34m(self, connection_args)\u001b[39m\n\u001b[32m    287\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m MilvusException \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[32m    288\u001b[39m     logger.error(\u001b[33m\"\u001b[39m\u001b[33mFailed to create new connection using: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[33m\"\u001b[39m, alias)\n\u001b[32m--> \u001b[39m\u001b[32m289\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m e\n",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\langchain_community\\vectorstores\\milvus.py:284\u001b[39m, in \u001b[36mMilvus._create_connection_alias\u001b[39m\u001b[34m(self, connection_args)\u001b[39m\n\u001b[32m    282\u001b[39m alias = uuid4().hex\n\u001b[32m    283\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m284\u001b[39m     \u001b[43mconnections\u001b[49m\u001b[43m.\u001b[49m\u001b[43mconnect\u001b[49m\u001b[43m(\u001b[49m\u001b[43malias\u001b[49m\u001b[43m=\u001b[49m\u001b[43malias\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mconnection_args\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    285\u001b[39m     logger.debug(\u001b[33m\"\u001b[39m\u001b[33mCreated new connection using: \u001b[39m\u001b[38;5;132;01m%s\u001b[39;00m\u001b[33m\"\u001b[39m, alias)\n\u001b[32m    286\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m alias\n",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\pymilvus\\orm\\connections.py:461\u001b[39m, in \u001b[36mConnections.connect\u001b[39m\u001b[34m(self, alias, user, password, db_name, token, _async, **kwargs)\u001b[39m\n\u001b[32m    458\u001b[39m         \u001b[38;5;28;01mif\u001b[39;00m parsed_uri.scheme == \u001b[33m\"\u001b[39m\u001b[33mhttps\u001b[39m\u001b[33m\"\u001b[39m:\n\u001b[32m    459\u001b[39m             kwargs[\u001b[33m\"\u001b[39m\u001b[33msecure\u001b[39m\u001b[33m\"\u001b[39m] = \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m461\u001b[39m     \u001b[43mconnect_milvus\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muser\u001b[49m\u001b[43m=\u001b[49m\u001b[43muser\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpassword\u001b[49m\u001b[43m=\u001b[49m\u001b[43mpassword\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mtoken\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtoken\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mdb_name\u001b[49m\u001b[43m=\u001b[49m\u001b[43mdb_name\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    462\u001b[39m     \u001b[38;5;28;01mreturn\u001b[39;00m\n\u001b[32m    464\u001b[39m \u001b[38;5;66;03m# 2nd Priority, connection configs from env\u001b[39;00m\n",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\pymilvus\\orm\\connections.py:411\u001b[39m, in \u001b[36mConnections.connect.<locals>.connect_milvus\u001b[39m\u001b[34m(**kwargs)\u001b[39m\n\u001b[32m    408\u001b[39m timeout = t \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(t, (\u001b[38;5;28mint\u001b[39m, \u001b[38;5;28mfloat\u001b[39m)) \u001b[38;5;28;01melse\u001b[39;00m Config.MILVUS_CONN_TIMEOUT\n\u001b[32m    410\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m _async:\n\u001b[32m--> \u001b[39m\u001b[32m411\u001b[39m     \u001b[43mgh\u001b[49m\u001b[43m.\u001b[49m\u001b[43m_wait_for_channel_ready\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m    413\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m kwargs.get(\u001b[33m\"\u001b[39m\u001b[33mkeep_alive\u001b[39m\u001b[33m\"\u001b[39m, \u001b[38;5;28;01mFalse\u001b[39;00m):\n\u001b[32m    414\u001b[39m     gh.register_state_change_callback(\n\u001b[32m    415\u001b[39m         ReconnectHandler(\u001b[38;5;28mself\u001b[39m, alias, kwargs_copy).reconnect_on_idle\n\u001b[32m    416\u001b[39m     )\n",
      "\u001b[36mFile \u001b[39m\u001b[32mE:\\ProgramData\\miniconda3\\envs\\langchain\\Lib\\site-packages\\pymilvus\\client\\grpc_handler.py:153\u001b[39m, in \u001b[36mGrpcHandler._wait_for_channel_ready\u001b[39m\u001b[34m(self, timeout)\u001b[39m\n\u001b[32m    151\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m grpc.FutureTimeoutError \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[32m    152\u001b[39m     \u001b[38;5;28mself\u001b[39m.close()\n\u001b[32m--> \u001b[39m\u001b[32m153\u001b[39m     \u001b[38;5;28;01mraise\u001b[39;00m MilvusException(\n\u001b[32m    154\u001b[39m         code=Status.CONNECT_FAILED,\n\u001b[32m    155\u001b[39m         message=\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFail connecting to server on \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m._address\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m, illegal connection params or server unavailable\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m    156\u001b[39m     ) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01me\u001b[39;00m\n\u001b[32m    157\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[32m    158\u001b[39m     \u001b[38;5;28mself\u001b[39m.close()\n",
      "\u001b[31mMilvusException\u001b[39m: <MilvusException: (code=2, message=Fail connecting to server on 192.168.0.188:19530, illegal connection params or server unavailable)>"
     ]
    }
   ],
   "source": [
    "from langchain_community.vectorstores import Milvus\n",
    "\n",
    "my_emb = OllamaEmbeddings(base_url='http://localhost:11434', model=\"bge-m3:latest\")\n",
    "\n",
    "# Milvus 连接参数\n",
    "vectordb = Milvus(\n",
    "        embedding_function=my_emb,\n",
    "        collection_name=\"Vmaxs\",  # Milvus 集合名称\n",
    "        connection_args={\n",
    "            \"host\": \"192.168.0.188\",  # Milvus 服务器地址\n",
    "            \"port\": \"19530\",  # Milvus 默认端口\n",
    "        },\n",
    "    )\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
